package com.sxpi.course.service.coursePrise;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxpi.course.mapper.CoursePriseMapper;
import com.sxpi.course.pojo.CoursePrise;
import io.lettuce.core.RedisClient;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 董伟豪
 * @Date: 2022/11/15 11:04
 */
@Service
@Slf4j
public class CoursePriseServiceImpl extends ServiceImpl<CoursePriseMapper, CoursePrise> implements ICoursePriseService{

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 保存用户点赞信息 -- 无锁的方案
     * 如果用户疯狂点赞会怎么样？？？
     * @param coursePrise
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional
    public int insertCoursePrise(CoursePrise coursePrise) {
        // 判断用户是否已经点过赞
        LambdaQueryWrapper<CoursePrise> coursePriseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        coursePriseLambdaQueryWrapper.eq(CoursePrise::getCourseId,coursePrise.getCourseId());
        coursePriseLambdaQueryWrapper.eq(CoursePrise::getUserId,coursePrise.getUserId());
        CoursePrise coursePriseDB = this.getOne(coursePriseLambdaQueryWrapper);
        if(coursePriseDB == null){
            int i = baseMapper.insertCoursePrise(coursePrise);
            // 同步缓存

            return i > 0 ? 1 : 0;
        }else{
            // 如果存在就执行更新操作
            CoursePrise coursePrise1 = new CoursePrise();
            coursePrise1.setId(coursePriseDB.getId());
            coursePrise1.setStatus(1);
            this.updateById(coursePrise1);
        }
        return 1;
    }

    /**
     * 保存用户点赞信息 -- redis的锁（可重入）
     * 如果用户疯狂点赞会怎么样？？？
     * @param coursePrise
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    // @GlobalTransactional
    public int insertCoursePriseRedisLock(CoursePrise coursePrise){
        // 控制锁的力度
        String lockName = "redisson:course:" + coursePrise.getCourseId() + ":" + coursePrise.getUserId();
        RLock lock = redissonClient.getLock(lockName);
        // 上锁，10秒中只能点击一次，可以避免redis宕机时出现死锁，可以控制用户在点赞的时候10秒中点击一次
        lock.lock(10L, TimeUnit.SECONDS);
        try {
            // 分布式锁的key
            // 判断用户是否已经点过赞
            LambdaQueryWrapper<CoursePrise> coursePriseLambdaQueryWrapper = new LambdaQueryWrapper<>();
            coursePriseLambdaQueryWrapper.eq(CoursePrise::getCourseId,coursePrise.getCourseId());
            coursePriseLambdaQueryWrapper.eq(CoursePrise::getUserId,coursePrise.getUserId());
            CoursePrise coursePriseDB = this.getOne(coursePriseLambdaQueryWrapper);
            if(coursePriseDB == null){
                int i = baseMapper.insertCoursePrise(coursePrise);
                // 同步缓存

                return i > 0 ? 1 : 0;
            }else{
                // 如果存在就执行更新操作
                CoursePrise coursePrise1 = new CoursePrise();
                coursePrise1.setId(coursePriseDB.getId());
                coursePrise1.setStatus(1);
                this.updateById(coursePrise1);
            }
        }catch (Exception ex){
            throw new RuntimeException("CoursePriseServiceImpl保存服务发生异常");
            // 发邮件
        }finally {
            lock.unlock();
        }
        return 1;
    }

    /**
     * 查看某个用户的课程点赞记录
     * @param courseId
     * @param userId
     * @return
     */
    @Override
    public CoursePrise selectByCourseIdAndUserId(Long courseId, Long userId) {
        return baseMapper.selectByCourseIdAndUserId(courseId,userId);
    }

    /**
     * 根据课程id查询总的点赞记录
     * @param courseId
     * @return
     */
    @Override
    public int countByCourseId(Long courseId) {
        return baseMapper.countByCourseId(courseId);
    }

    /**
     * 用户取消课程的点赞记录
     * @param courseId
     * @param userId
     * @return
     */
    @Override
    public int cancelCoursePrise(Long courseId, Long userId) {
        return baseMapper.cancelCourseParise(courseId,userId);
    }

    /**
     * 获取课程的点赞的总数排行
     * @return
     */
    @Override
    public List<Map<String, Object>> getCoursePriseRank() {
        return baseMapper.getCoursePariseRank();
    }
}
